package upm.pb4agent.common;

import upm.pb4agent.ontology.EnteringDock;
import upm.pb4agent.ontology.PB4AgentOntology;
import upm.pb4agent.ontology.RaceFinished;
import upm.pb4agent.ontology.RaceStarted;
import upm.pb4agent.ontology.Row;
import upm.pb4agent.ontology.SubscribeReferee;
import upm.pb4agent.team8.Common.PB4Utils;
import upm.pb4agent.team8.Common.PB4Utils.MsgTypes;
import jade.content.Concept;
import jade.content.ContentElement;
import jade.content.lang.Codec;
import jade.content.lang.sl.SLCodec;
import jade.content.onto.Ontology;
import jade.content.onto.basic.Action;
import jade.core.AID;
import jade.core.Agent;
import jade.core.behaviours.CyclicBehaviour;
import jade.core.behaviours.SimpleBehaviour;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;
import jade.util.leap.ArrayList;
import jade.util.leap.List;

public class Referee extends Agent
{
	private Codec codec = new SLCodec();
	private Ontology ontology = PB4AgentOntology.getInstance();
	private List SubscribersList = new ArrayList();
	
	protected void setup()
	{
		getContentManager().registerLanguage(codec);
		getContentManager().registerOntology(ontology);
	      
		PB4Utils.Console.WriteLine(getLocalName() + ": Enters the system");
		PB4Utils.TryRegisterAgent(this, Constant.REFEREE);
		this.addBehaviour(new RegisterObserversListener(this));
		this.addBehaviour(new SendEventSubscribersBehavior(this));
	}
	
	private void SendSuscribersEventMessagee(AID receiverID, Concept concept)
	{
		PB4Utils.TrySendConceptMessage(ACLMessage.INFORM, this, receiverID, concept);
	}

	private void NotifySubscribersEvent(Concept concept)
	{
		for (int i = 0; i < SubscribersList.size(); i++)
		{	
			SendSuscribersEventMessagee((AID)SubscribersList.get(i), concept);
		}
	}

	public class RegisterObserversListener extends CyclicBehaviour
	{
		private Agent _agent;
		public RegisterObserversListener (Agent agent)
		{
			super(agent);
			_agent=agent;
		}
		
		@Override
		public void action()
		{       
			ACLMessage msg = receive(MessageTemplate.MatchProtocol(PB4AgentOntology.SUBSCRIBEREFEREE));
			if (msg != null)
			{
				ContentElement content = PB4Utils.GetMessageContent(_agent, msg);					
				switch (msg.getPerformative()) 
				{
				case ACLMessage.SUBSCRIBE:
					Concept action = ((Action)content).getAction();
					if (action instanceof SubscribeReferee )
					{						
						SubscribersList.add((AID)msg.getSender());
						PB4Utils.Console.WriteLine("Subscription for Notification messages arrived to Referee from " + msg.getSender().getLocalName() + " arrived", MsgTypes.Standard);
					}
					break;
				}
			}
		}
	}	

	public class SendEventSubscribersBehavior extends SimpleBehaviour
	{
		private Agent _agent;
		private boolean _finished = false;
		public SendEventSubscribersBehavior(Agent agent)
		{
			super(agent);
			_agent=agent;
		}
		
		@Override
		public void action() 
		{
			ACLMessage msg = receive(MessageTemplate.or(
									 MessageTemplate.or(
									 MessageTemplate.or(
									 MessageTemplate.MatchProtocol(PB4AgentOntology.RACESTARTED),
									 MessageTemplate.MatchProtocol(PB4AgentOntology.ENTERINGDOCK)),
									 MessageTemplate.MatchProtocol(PB4AgentOntology.LEAVINGDOCK)),
									 MessageTemplate.MatchProtocol(PB4AgentOntology.RACEFINISHED)));
									 
			if (msg != null) 
	        {
		    	ContentElement content = PB4Utils.GetMessageContent(_agent, msg);
		        switch (msg.getPerformative()) 
		        {			        			
		         	case (ACLMessage.INFORM):
		         		Concept msgAction = ((Action)content).getAction();
						NotifySubscribersEvent(msgAction);
						if (msgAction instanceof RaceFinished )
						{
							RaceFinished race = (RaceFinished)msgAction;
							PB4Utils.Console.WriteLine("RACE FINISHED!!!", MsgTypes.Standard);
							PB4Utils.Console.WriteLine(race.getBoatAID().getLocalName() + " finished the race in position # " + race.getPosition(), MsgTypes.Standard);
						}
						_finished = true;
						break;
		         }
	        }
		}
				
		@Override
		public boolean done()
		{
			return false;
		}
	}
}
